#include "plugin.h"

#include <string.h>

// ----------------------------------------------------------------------------
XCALL_(LWInstance) BWCreate(void *priv, void *context, LWError *err) 
{
    BWInstanceData* instance = NULL;
    int* ipContext = (int*)context;
        
    if (context != NULL && *ipContext & LWFCF_PREPROCESS)
    {
        *err = "Preprocessing is not yet supported";
        return NULL;
    }

    instance = calloc(1, sizeof(BWInstanceData));
    if (instance)
    {
        instance->globalFunc = priv;        
        instance->depthBuffer = NULL;
        instance->pixelBuffer = NULL;
        instance->particleList = NULL;
        instance->filterAccess = NULL;        
        instance->numProcessedTriangles = 0;
        instance->projMatrixDirty = TRUE;
         
        // set default options
        instance->renderParticlesOnly = FALSE;
        instance->writeTrace = TRUE;
    }
    else
    {
        *err = "Could not allocate memory for instance data!";        
    }
    
    return instance;
}

// ----------------------------------------------------------------------------
XCALL_(void) BWDestroy(RenderSettings* inst) 
{
    if (inst) free(inst);
}

// ----------------------------------------------------------------------------
XCALL_(LWError) BWCopy(BWInstanceData* to, BWInstanceData* from) 
{ 
    //*to = *from;   
    return NULL; 
}

// ----------------------------------------------------------------------------
XCALL_(unsigned int) BWFlags (LWInstance inst) 
{
   return 1 << LWBUF_DEPTH;
}

// ----------------------------------------------------------------------------
XCALL_(const char *) BWDescribe(BWInstanceData *inst) 
{ 
    static char description[256];
    sprintf_s(description, 256, "BrushWave - Painterly Rendering (v%d.%d)", 
        VERSION_MAJOR, VERSION_MINOR);    
    return description; 
}

// ----------------------------------------------------------------------------
XCALL_(const LWItemID*) BWUseItems(BWInstanceData *inst) 
{ 
    return NULL; 
}

// ----------------------------------------------------------------------------
XCALL_(void) BWChangeID(BWInstanceData *inst, const LWItemID *ids) 
{ }

// ----------------------------------------------------------------------------
XCALL_(static void) BWProcess(BWInstanceData* instance, const LWFilterAccess *fa) 
{
    /* LightWave calls the process function to process each rendered frame.
       The processing function has to call setRGB() and setAlpha() for every
       pixel in the image, even if only a few, or none, are changed. 
    */
        
    int numParticles;
    BOOL success;

    clearGLerrors();

    WriteTrace("::: Starting to process (frame %d) :::", 
        getLWTimeInfo(instance->globalFunc)->frame);

    WriteTrace("Using the following global settings:");
    WriteTrace("  Render particles only: %d", instance->renderParticlesOnly);
    
    instance->filterAccess = fa;
    instance->particleList = NULL;
    
    // fire up the monitor 
    MON_INIT(fa->monitor, 5);        

    success = PrepareBuffers(instance);
    if (!success) 
    {
        showLWMessage(instance->globalFunc, LWMsgType_Error, 
            "Could not prepare rendering buffers for Brushwave rendering!",
            NULL);
    }
    incrementLWMonitor(fa->monitor, TRUE);
    
    ProcessScene(instance);
    incrementLWMonitor(fa->monitor, TRUE);

    instance->particleList = SortList(instance->particleList, FALSE);    
    incrementLWMonitor(fa->monitor, TRUE);
    
    DrawParticles(instance);
    incrementLWMonitor(fa->monitor, TRUE);

    // free ressources
    numParticles = ClearList(instance->particleList);
    WriteTrace("Deleted %d particles.", numParticles);    
    
    ReleaseTextures(instance);
    ReleaseBuffers(instance);

    // clear unusable data
    instance->filterAccess = NULL;
    instance->particleList = NULL;

    WriteTrace("::: Finished processing! :::");

    MON_DONE( fa->monitor );
}


// ----------------------------------------------------------------------------
XCALL_(int) BWActivate (long version, GlobalFunc *globalFunc, 
                        LWImageFilterHandler *local, void *serverData) 
{   
    if (version != LWIMAGEFILTER_VERSION) return AFUNC_BADVERSION;

    local->inst->create  = BWCreate;
    local->inst->destroy = BWDestroy;
    local->inst->copy    = BWCopy;
    local->inst->load    = BWLoad;
    local->inst->save    = BWSave;
    local->inst->descln  = BWDescribe;
    local->inst->priv    = globalFunc; // save global func to be able to access
                                       // it in the create function

    if (local->item) 
    {
        local->item->useItems = BWUseItems;
        local->item->changeID = BWChangeID;
    }

    local->process = BWProcess;
    local->flags   = BWFlags;    
    
    return AFUNC_OK;
}


// ----------------------------------------------------------------------------
XCALL_(int) BWUiActivate (long version, GlobalFunc *globalFunc, 
                          LWInterface *ui, void *serverData) 
{    
    BWInstanceData* instance;
    
    if (version != LWINTERFACE_VERSION) return (AFUNC_BADVERSION);

    instance = (BWInstanceData*) ui->inst;

    ui->panel   = BWCreatePanel(instance);
    ui->options = NULL;
    ui->command = NULL;

    return AFUNC_OK;
}